package com.automapper.interceptor;

import java.sql.Connection;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.automapper.constants.EnumAction;
import com.automapper.execute.Execute;
import com.automapper.execute.ExecuteFactory;
import com.automapper.utils.MetaObjectUtils;
import com.automapper.utils.PropertiesFacade;

/**
 * mybatis拦截器<br>
 * 通过拦截<code>StatementHandler</code>的<code>prepare</code>
 * 方法，根据参数parameterObject配置的注解信息，自动生成sql语句。 
 * 签名里要拦截的类型只能是接口。
 * @author K
 *
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class AutoMapperInterceptor implements Interceptor {
	private static final Logger log = LoggerFactory.getLogger(AutoMapperInterceptor.class);
	
    private PropertiesFacade propertiesFacade = null;
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		//MetaObject是Mybatis提供的一个的工具类,用于获取属性的值（支持OGNL的方法）
		MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
		metaStatementHandler = MetaObjectUtils.getOriginalMetaObject(metaStatementHandler);
		//获取mapper文件的sql语句
		String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
		
		MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
		
		// 根据ID生成相应类型的sql语句（id需剔除namespace信息）
		String id = mappedStatement.getId();
		id = id.substring(id.lastIndexOf('.') + 1);
		//只有sql是空并且是调用AutoMapperRepository对象的方法才会走if里面的方法
		if (StringUtils.isBlank(originalSql) && id.equalsIgnoreCase(EnumAction.getValue(id))) {
			log.debug("请使用mybatis 3.3.1或更新的版本");
			Execute execute = ExecuteFactory.getInstance(id);
			execute.process(metaStatementHandler, invocation, propertiesFacade);
		}
		
		// 传递给下一个拦截器处理
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		if (target == null) {
			return target;
		}
		return Plugin.wrap(target, this);  
	}
	
	/**
	 * 插件参数<br>
	 * 现在支持参数有：<br>
	 * <p>isNullToDefaultValue: 如果是true，POJO对象里String类型属性值是空，赋值字符串；
	 * POJO对象里Integer，Long，Double类型的属性是空， 赋值0；
	 * 如果是false，POJO对象的属性的值是空不会给默认值
	 * <p>byteCodeFrameworkType: 指定用byteCodeFramework动态生成类，如果没有指定，默认使用javassist
	 * @param properties
	 */
	@Override
	public void setProperties(Properties properties) {
		this.propertiesFacade = new PropertiesFacade(properties);
	}
}
